package an_sim;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;

/**
 * Ez az osztály tárolja az egész hálózatot.
 * Felelős a szimulációk megfelelő lefuttatásáért.
 * @author D-Torus-Team
 */

public class FullNetwork {

    private List<VirtualNetwork> virtualNetworkList;
    private List<Node> nodeList;

    /**
     * Konstruktor. A paraméterként kapott Node lista alapján minden egyes nodra létrehoz egy egy tagú vn-t.
     * A SuperNode a Node-ok tulajdonságaival fog rendelkezni.
     * Kezdetben a hierarchiaszint nulla, és nincs le és fel mutató ID.
     * @param n node lista
     */

    FullNetwork(List<Node> n) {
        virtualNetworkList = new ArrayList<VirtualNetwork>();
        this.nodeList = new ArrayList<Node>();
        this.nodeList.addAll(n);
        Iterator<Node> it = nodeList.iterator();
        while (it.hasNext()) {
            List<Node> temp = new ArrayList();
            temp.add(it.next());
            List<Integer> Down=new ArrayList();
            virtualNetworkList.add(new VirtualNetwork(temp, temp.get(0).getPolicy(), 0, Down, 0));
            temp.clear();
        }
    }

//    FullNetwork(List<VirtualNetwork> vn){
//        virtualNetworkList=vn;
//
//    }

    public List<VirtualNetwork> getVirtualNetworkList() {
        return this.virtualNetworkList;
    }

    public List<Node> getNodeList() {
        return this.nodeList;
    }

    /**
     * Egy szimulációs lépést megvalósító függvény.
     * @param rand random szimuláció ha igaz, irányított egyébként
     * @param vn irányított esetben kezdeményező fél
     * @param vnn irányított esetben a kezdeményező fél egy szomszédja
     * @param r egy random generátor
     */

    public void simulate(boolean rand, VirtualNetwork vn, VirtualNetwork vnn, Random r) {
        // Ez a változó jelzi, hogy volt-e sikeres abszorbció, azaz nem kell átlépni a gatewaying ágba
        // Alap esetben false
        boolean canAbs = false;

        // Létrehozunk egy új vn-t, amire a rand(boolean) változótól függően,
        //vagy az átadott vn, vagy a listából a random generátor által véletlen kiválasztott vn mutatóját állítjuk
        VirtualNetwork A = null;
        int random = r.nextInt(virtualNetworkList.size());
        if (rand) {
            System.out.println("Random szám: " + random);
            A = virtualNetworkList.get(random);
        } else {
            A = vn;
        }


        // Ha random szimuláció lesz
        if (rand) {
            System.out.println("\t \tRandom szimuláció!");
            // Végigmegyünk a fentebb kiválaszott Node szomszédain és megnézzük lehet-e abszorbció
            Iterator<Integer> it = A.getNeighbours().iterator();
            while (it.hasNext()) {
                VirtualNetwork B = getVNByID(it.next());
                if (B == null) {
                    return;
                }
                if (A.getSuperNode().getPolicy().checkPolicy(B.getSuperNode().getPolicy())) {
                    // Ha igen akkor lefuttatjuk és beállítjuk a canABs változót true-ra, hogy ne probáljon gatewayezni
                    B.absorbtion(A, this);
                    canAbs = true;
                    break;
                }
            }

            // Ha nem sikerült az abszorbció egy szomszéddal sem
            if (!canAbs) {
                // Végigmegyünk a szomszédain és gatewayezünk, majd beletesszük a hálózat listájába az új vn-t
                it = A.getNeighbours().iterator();
                while (it.hasNext()) {
                    VirtualNetwork B = getVNByID(it.next());
                    if (!(A.getSuperNode().getPolicy().checkPolicy(B.getSuperNode().getPolicy()))) {
                        VirtualNetwork temp = B.gatewaying(A, this);
                        if (temp != null) {
                            if (temp.getHierarchyLevel() == -10) {
                                break;
                            }
                            this.virtualNetworkList.add(temp);
//                            System.out.println("********************************************");
//                            System.out.println("Az éppen hozzáadott elem:");
//                            printSuperNode(temp.getSuperNode().getID());
//                            System.out.println("********************************************");
                            break;
                            
                        }
                    }
                }
            }
        } else {
            System.out.println(" \t \t Irányított szimuláció! ");
            if (A.getSuperNode().getPolicy().checkPolicy(vnn.getSuperNode().getPolicy())) {
                vnn.absorbtion(A, this);
                // this.virtualNetworkList.remove(A);
                canAbs = true;
            }
            if (!canAbs) {
                if (!(A.getSuperNode().getPolicy().checkPolicy(vnn.getSuperNode().getPolicy()))) {
                    VirtualNetwork temp = vnn.gatewaying(A, this);
                    if (temp != null) {
                        if (temp.getHierarchyLevel() == -10) {
                                return;
                            }
                        this.virtualNetworkList.add(temp);
//                            System.out.println("********************************************");
//                            System.out.println("Az éppen hozzáadott elem:");
//                            printSuperNode(temp.getSuperNode().getID());
//                            System.out.println("********************************************");
                            return;
                    }

                }

            }
        }
    }

    public VirtualNetwork getVNByID(int id) {
        Iterator<VirtualNetwork> it = virtualNetworkList.iterator();
        while (it.hasNext()) {

            VirtualNetwork temp = it.next();
            if (temp.getSuperNode().getID() == id) {
                return temp;
            }
        }
        System.out.println(" getVNByID null Keresett ID nem található!" + id);
        return null;
    }

    public void fullSimulate(boolean rand, VirtualNetwork vn, VirtualNetwork vnn) {
        Random r = new Random(); //56921
        int counter = 10;
        int c = 0;
        Iterator<VirtualNetwork> vnIt = this.virtualNetworkList.iterator();
        while (counter != 1) {
            counter = 0;
            System.out.print(" \n =========== Akik felett nincs gw: ");
            while (vnIt.hasNext()) {
                VirtualNetwork temp = vnIt.next();
                if (temp.getGatewayIdUp() == 0) {
                    System.out.print(temp.getSuperNode().getID() + " | ");
                    counter++;
                }

            }
            if (counter == 1) {
                return;
            }

            System.out.println("Számláló: " + counter);
            System.out.print(" ---------------------> Szimuláció: " + ++c + " <----------------------------------- ");
            if (counter == 2) {  //ha már csak kettő maradt, akkor azok rögötn találkozzanak
                vnIt = this.virtualNetworkList.iterator();
                VirtualNetwork a = null;
                VirtualNetwork b = null;
                while (vnIt.hasNext()) {
                    VirtualNetwork temp = vnIt.next();
                    if (temp.getGatewayIdUp() == 0) {
                        if (a == null) {
                            a = temp;
                        } else if (b == null) {
                            b = temp;
                        }

                    }
                }
                simulate(false, a, b, r);
                //printAllVirtualNetwork();
                return;
            } else {
                simulate(rand, vn, vnn, r);
              //  printAllVirtualNetwork();
                vnIt = this.virtualNetworkList.iterator();
            }
        }

    }

//    /*********************************************DEBUGHOZ****************************************************************/
//    public void printSuperNode(int VNid) {
//
//        VirtualNetwork temp = this.getVNByID(VNid);
//        System.out.println("║ ┌───────────────┐");
//        System.out.println("║ │ID: " + temp.getSuperNode().getID());
//        System.out.println("║ │Policy: P:" + temp.getSuperNode().getPolicy().getProvided() + " R:" + temp.getSuperNode().getPolicy().getRequired());
//        Iterator<Integer> it = temp.getSuperNode().getNeighbours().iterator();
//        System.out.print("║ │Neighbours: ");
//        while (it.hasNext()) {
//            System.out.print(it.next() + " ");
//        }
//        System.out.println(";");
//        System.out.println("║ └───────────────┘");
//
//    }
//
//    public void printVirtualNetwork(int VNid) {
//        VirtualNetwork temp = this.getVNByID(VNid);
//        System.out.println("╔════════════════════════════╗");
//        printSuperNode(VNid);
//        Iterator<Node> it = temp.getMembers().iterator();
//
//        System.out.print("║Member IDs: ");
//        while (it.hasNext()) {
//            System.out.print(it.next().getID() + " ");
//        }
//        System.out.println();
//        System.out.println("║Level: " + temp.getHierarchyLevel() + " Busy: " + temp.isBusy());
//        Iterator<Integer> gwD=temp.getGatewayIdDown().iterator();
//        System.out.print("║Gateway ID Down: ");
//        while(gwD.hasNext()){
//            System.out.print(gwD.next()+ " ");
//        } System.out.println();
//        System.out.println("║Gateway ID Up: " + temp.getGatewayIdUp());
//        System.out.println("║Time: "+ temp.getTime().getSumTime());
//        System.out.println("╚════════════════════════════╝");
//    }
//
//    public void printAllSuperNode() {
//        Iterator<VirtualNetwork> it = this.getVirtualNetworkList().iterator();
//        while (it.hasNext()) {
//            printSuperNode(it.next().getSuperNode().getID());
//        }
//
//
////        int i=0;
////        while(i!=this.fn.getNodeListSize()){
////            printSuperNode(i);
////            i++;
////        }
//    }
//
//    public void printAllVirtualNetwork() {
//        try {
//            Iterator<VirtualNetwork> it = this.getVirtualNetworkList().iterator();
//            while (it.hasNext()) {
//                printVirtualNetwork(it.next().getSuperNode().getID());
//            }
//        } catch (Exception e) {
//            System.out.println("HIBA::::::::" + e.getMessage());
//        }
//    }
//    /*********************************************************************************************/
}
